Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Script] Inspiration

August 06 (5 years ago)

Edited August 06 (5 years ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

I have written a truckload of macros, but this is my first ever api script. I hope some folks find it useful. If you find problems, let me know. But be patient. :) Huge thanks to the Aaron and Scott C., for their advice, guidance and cleanup on Aisle 3.


I have tried many ways to remember to use inspiration in D&D 5e. If I use a status marker, it gets overlooked. I have started using a card deck, but it breaks the action if I stop to show the deck, draw a card and give it to a player. This script does that automatically. In order for it to work, you need to create a new deck in your game, named "Inspiration". It should have one card (whatever symbol you want to represent inspiration), and it should be set to be infinite, so there is always a card available to draw. For mine, I used the "Angel" coin from the reign of Edward IV. It's in the wikimedia commons, so I include it at the bottom if you want to use that.

To give inspiration to a player, select their token. You must select only one token, it must represent a character, and that character has to be controlled by at least one player (Only players get inspiration). The character can be controlled by All players, or multiple players or both, but the script will select the first single player controller in the controlled by list.


The script has two commands:

!inspire --give or !inspire will deal an inspiration card to a player. I recommend putting this on a macro button for quick awarding.

!inspire --take will recall the card from the player when it is spent. I recommend players having this as a token action. Playing a card has proved to cause action to crawl to a stop if your player are unused to the card interface.


Here are the macros I use. You of course, can write your own. These use Roll20 Audio Master to give it some dramatic flair:

For awarding

!roll20AM --audio,play,nomenu|name_of_inspiration_award_track
!inspire
&{template:npcaction} {{rname=Congratulations!}} {{description=**@{selected|character_name} has just been granted Inspiration!**
[x](URL_of_inspiration_card_image)}}


For spending:

!roll20AM --audio,play,nomenu|name_of_inspiration_spending_track
!inspire --take
&{template:npcaction} {{rname=Inspiration!}} {{description=**@{selected|character_name} has just spent their Inspiration!**
[x](URL_of_inspiration_card_image)}}


Inspiration

on('chat:message', (msg) => {
    if ('api' === msg.type && /!inspire\b/i.test(msg.content) && msg.selected) {
        //get parameter and use default of 'give' if parameter is missing or malformed
        let cardAction = msg.content.split(/\s+--/)[1];
        if ((cardAction !== "give" && cardAction !== "take") || cardAction === false) {
            cardAction = 'give';
        }
        //getid of deck
        let inspirationDeck = findObjs({
            _type: "deck",
            name: "Inspiration"
        })[0];

        //test if deck exists
        if (inspirationDeck) {

            let deckID = inspirationDeck.id;
            // Necessary to shuffle at least once after deck creation because of Roll20 Deck bug
            shuffleDeck(deckID);
            //get id of card
            let cardid = drawCard(deckID);

            // get playerId of Token controller
            //assign selected token to a variable

            log('number of tokens selected is ' + msg.selected.length);
            if (msg.selected.length <= 1) {

                let token = getObj(msg.selected[0]._type, msg.selected[0]._id);

                //assign associated character to a variable
                if (token.get('represents')) {
                    let character = getObj("character", token.get('represents'));

                    //Get owner IDs of each -- Not needed at this point
                    //tokenOwner = (token.get('controlledby').split(',')[0]);
                    //characterOwner = (character.get('controlledby').split(',')[0]);
                    // If the token represents a character, get the character's controller, otherwise the token's
                    let ownerids = (token.get('controlledby').split(','));


                    if (character) {
                        ownerids = (character.get('controlledby').split(','));
                    }
                    //reduces to one ownerid that is not ['all']
                    ownerid = ownerids.filter(s => s !== 'all')[0];


                    // give card to player
                    // If the ownerid is not undefined (i.e. there is a valid controller) perform the transaction
                    if (ownerid) {

                        switch (cardAction) {
                            case 'take':
                                takeCardFromPlayer(ownerid, {
                                    cardid: cardid
                                });
                                break;
                            default:
                                giveCardToPlayer(cardid, ownerid);
                                break;

                        }

                    } else {

                        sendChat('Inspire', '/w gm If a token represents a character controlled by \'All Players\', an individual player must be also be specified. If there are multiple controllers, only the first will get inspiration.');
                    }
                } else {
                    sendChat('Inspire', '/w gm This token does not represent a player character. Only players get Inspiration.');
                }
            } else {
                sendChat('Inspire', '/w gm Please select only one token. It must represent player-controlled character.');
            }
        } else {
            sendChat('Inspire', '/w gm Create a deck named Inspiration.It must be an infinite deck of one card only.');
        }
    }
});

And a Screenshot, using the macros above:

Coin Image if you want to use it.
This file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license.
Attribution: Classical Numismatic Group, Inc. http://www.cngcoins.com
August 06 (5 years ago)
GiGs
Pro
Sheet Author
API Scripter

Very nice!

August 06 (5 years ago)
The Aaron
Roll20 Production Team
API Scripter

Woot!  Nice work!

August 06 (5 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Nice job Keith!

August 06 (5 years ago)
Ravenknight
KS Backer
Good work!

Awesome!

August 12 (5 years ago)

Nice script Keith....I'm shamelessly stealing it.  My group is new to 5e, and we didn't even know "Inspiration" existed until I saw this posting!  Thanks for the script, and thanks for opening our eyes to a new 5e rule!

August 12 (5 years ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

Cool. The reason I wrote it was because I did know about the rule, but could never remember to use it! :D

August 12 (5 years ago)

Yeah very nice script Keith. It works for other decks to if you change the name which can help with some twitch games. So thank you.

August 12 (5 years ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

Bonus! With a little more tweaking you could have a version for different decks. I might want to handle Bardic inspiration that way.

August 14 (5 years ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

And I have tweaked it sufficiently to warrant a new name and new thread: Dealer.